using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ApplicationServer.Caching;
using PostSharp.Aspects;

namespace CacheAspect.Attributes
{
    public static partial class Cache
    {
        [Serializable]
        public class Cacheable : OnMethodBoundaryAspect
        {
            private KeyBuilder _keyBuilder;
            public KeyBuilder KeyBuilder
            {
                get { return _keyBuilder ?? (_keyBuilder = new KeyBuilder()); }
            }

            #region Constructors
            
            public Cacheable(String groupName, CacheSettings settings, String parameterProperty)
            {
                KeyBuilder.GroupName = groupName;
                KeyBuilder.Settings = settings;
                KeyBuilder.ParameterProperty = parameterProperty;
            }

            public Cacheable(String groupName, CacheSettings settings)
                : this(groupName, settings, string.Empty)
            {
            }

            public Cacheable(String groupName) : this(groupName, CacheSettings.Default)
            {
            }

            public Cacheable() : this(string.Empty)
            {

            }
            #endregion

            // This method is executed before the execution of target methods of this aspect.
            public override void OnEntry(MethodExecutionArgs args)
            {
                // Compute the cache key.
                string cacheKey = KeyBuilder.BuildCacheKey(args.Instance, args.Arguments);

                // Fetch the value from the cache.
                ICache cache = CacheService.Cache;
                object value = cache.Contains(cacheKey) ? cache[cacheKey] : null;

                if (value != null)
                {
                    // The value was found in cache. Don't execute the method. Return immediately.
                    args.ReturnValue = value;
                    args.FlowBehavior = FlowBehavior.Return;
                }
                else
                {
                    // The value was NOT found in cache. Continue with method execution, but store
                    // the cache key so that we don't have to compute it in OnSuccess.
                    args.MethodExecutionTag = cacheKey;
                }
            }

            // This method is executed upon successful completion of target methods of this aspect.
            public override void OnSuccess(MethodExecutionArgs args)
            {
                string cacheKey = (string)args.MethodExecutionTag;
                CacheService.Cache[cacheKey] = args.ReturnValue;
            }

        }
    }

}

